package com.crane.oss.web.controller.school;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.crane.common.core.dto.MultiResponse;
import com.crane.common.core.dto.Response;
import com.crane.common.core.dto.SingleResponse;
import com.crane.common.core.exception.AppException;
import com.crane.common.core.exception.BasicErrorCode;
import com.crane.common.core.utils.StringUtil;
import com.crane.common.framework.utils.BeanUtil;
import com.crane.oss.listener.UploadStudentExcelListener;
import com.crane.oss.school.bean.request.QueryClassesReq;
import com.crane.oss.school.bean.request.QueryStudentReq;
import com.crane.oss.school.bean.request.QueryWaitingStudentReq;
import com.crane.oss.school.bean.request.student.AddLayerClassesReq;
import com.crane.oss.school.bean.request.student.AddStudentReq;
import com.crane.oss.school.bean.request.student.BatchChangeStudentReq;
import com.crane.oss.school.bean.request.student.BatchDeleteStudentReq;
import com.crane.oss.school.bean.request.student.BatchImportStudentEntity;
import com.crane.oss.school.bean.request.student.BatchUpdateSnReq;
import com.crane.oss.school.bean.request.student.ChangeStudentReq;
import com.crane.oss.school.bean.request.student.DeleteStudentReq;
import com.crane.oss.school.bean.request.student.UpdateStudentReq;
import com.crane.oss.school.bean.resp.StudentExportResp;
import com.crane.oss.school.bean.resp.StudentResp;
import com.crane.oss.school.bean.resp.StudentSimpleResp;
import com.crane.oss.school.service.ClassesInfoService;
import com.crane.oss.school.service.StudentService;
import com.crane.oss.web.BaseBusinessController;

import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;


/**
 * @author zhenxing.pi
 * @email ccsu123456@qq.com
 * @date 2022年03月26日 14时24分54秒
 */

@Api(value = "StudentController", tags = {"学生管理"})
@RestController
@RequestMapping("/school/student")
public class StudentController extends BaseBusinessController {

    @Autowired
    StudentService studentService;

    @Autowired
    ClassesInfoService classesInfoService;

	@ApiOperation(value = "班级下拉列表", notes = "获取班级下拉列表值")
	@ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "QueryClassesReq")
	@RequiresPermissions("school:student:classes")
	@PostMapping("/classes")
	public MultiResponse classes(@RequestBody QueryClassesReq request) {
		request.setPartyId(getPartyId());
		List<Map<String, Object>> list = classesInfoService.queryClassesForDropDown(request);
		return MultiResponse.ofWithoutTotal(list);
	}
	
	@ApiOperation(value = "待入分层班学生列表", notes = "获取待入分层班学生列表，页大小不要用默认值")
	@ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "QueryWaitingStudentReq")
	@RequiresPermissions("school:student:waiting")
	@PostMapping("/list/waiting")
	public MultiResponse<StudentSimpleResp> classes(@RequestBody QueryWaitingStudentReq request) {
		request.setPartyId(getPartyId());
		IPage<StudentSimpleResp> page = studentService.waiting(request);
		return MultiResponse.of(page.getRecords(), (int) page.getTotal(), request);
	}

    @ApiOperation(value = "学生列表", notes = "获取学生列表信息")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "QueryStudentReq")
    @RequiresPermissions("school:student:list")
    @PostMapping("/list")
    public MultiResponse<StudentResp> list(@RequestBody QueryStudentReq request) {
    	request.setPartyId(getPartyId());
        IPage<StudentResp> page = studentService.queryList(request);
        return MultiResponse.of(page.getRecords(), (int) page.getTotal(), request);
    }

    @ApiOperation(value = "学生详细", notes = "获取学生详细信息")
    @ApiImplicitParam(name = "studentId", value = "学生ID", paramType = "path", dataType = "String")
    @RequiresPermissions("school:student:info")
    @GetMapping("/info/{studentId}")
    public SingleResponse<StudentResp> info(@PathVariable("studentId") String studentId) {
        StudentResp studentResp = studentService.queryStudent(Long.valueOf(studentId));
        studentResp.setPartyName(getUser().getRealName());
        return SingleResponse.of(studentResp);
    }

    @ApiOperation(value = "行政班：单个添加", notes = "单个添加学生")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "AddStudentReq")
    @RequiresPermissions("school:student:save")
    @PostMapping("/save")
    public Response save(@RequestBody @Valid AddStudentReq request) {
    	request.setCreateUesrId(getUserId());
        request.setPartyId(getPartyId());
        studentService.save(request);
        return Response.buildSuccess();
    }

    @ApiOperation(value = "编辑/修改编号", notes = "编辑学生/修改编号")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "UpdateStudentReq")
    @RequiresPermissions("school:student:update")
    @PostMapping("/update")
    public Response update(@RequestBody @Valid UpdateStudentReq request) {
    	request.setPartyId(getPartyId());
    	request.setUpdateUserId(getUserId());
        studentService.update(request);
        return Response.buildSuccess();
    }
    
    @ApiOperation(value = "批量删除学生", notes = "批量删除学生")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "BatchDeleteStudentReq")
    @RequiresPermissions("school:student:batchDelete")
    @PostMapping("/batchDelete")
    public Response batchDelete(@RequestBody @Valid BatchDeleteStudentReq request) {
    	request.setPartyId(getPartyId());
    	request.setUpdateUserId(getUserId());
        studentService.batchDelete(request);
        return Response.buildSuccess();
    }

    @ApiOperation(value = "删除学生", notes = "删除学生")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "DeleteStudentReq")
    @RequiresPermissions("school:student:delete")
    @PostMapping("/delete")
    public Response delete(@RequestBody @Valid DeleteStudentReq request) {
    	request.setPartyId(getPartyId());
    	request.setUpdateUserId(getUserId());
        studentService.delete(request);
        return Response.buildSuccess();
    }
    
    @ApiOperation(value = "批量转班", notes = "批量转班")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "BatchChangeStudentReq")
    @RequiresPermissions("school:student:batchChange")
    @PostMapping("/batchChange")
    public Response batchChange(@RequestBody @Valid BatchChangeStudentReq request) {
    	request.setPartyId(getPartyId());
    	request.setUpdateUserId(getUserId());
        studentService.batchChange(request);
        return Response.buildSuccess();
    }

    @ApiOperation(value = "转班", notes = "学生转班")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "ChangeStudentReq")
    @RequiresPermissions("school:student:change")
    @PostMapping("/change")
    public Response change(@RequestBody @Valid ChangeStudentReq request) {
    	request.setPartyId(getPartyId());
    	request.setUpdateUserId(getUserId());
        studentService.change(request);
        return Response.buildSuccess();
    }
    
    @ApiOperation(value = "分层班：添加学生", notes = "学生加入分层班")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "AddLayerClassesReq")
    @RequiresPermissions("school:student:join")
    @PostMapping("/layer/join")
    public Response save(@RequestBody @Valid AddLayerClassesReq request) {
    	request.setCreateUesrId(getUserId());
        request.setPartyId(getPartyId());
        studentService.join(request);
        return Response.buildSuccess();
    }
    
    @ApiOperation(value = "分层班：批量改编号", notes = "批量改编号")
    @ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "BatchUpdateSnReq")
    @RequiresPermissions("school:student:batchUpdate")
    @PostMapping("/batchUpdate")
    public Response update(@RequestBody @Valid BatchUpdateSnReq request) {
    	request.setUpdateUserId(getUserId());
        studentService.batchUpdate(request);
        return Response.buildSuccess();
    }
    
	@ApiOperation(value = "下载模板", notes = "下载模板")
	@RequiresPermissions("school:student:download")
	@GetMapping("/download")
	public void download(HttpServletResponse response) {
		String dir = System.getProperty("user.dir") + "/";
		String path = dir + "student.xlsx";
		try {
			File file = new File(path);
			String filename = file.getName();

			InputStream fis = new BufferedInputStream(new FileInputStream(path));
			byte[] buffer = new byte[fis.available()];
			fis.read(buffer);
			fis.close();

			response.reset();

			response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
			response.addHeader("Content-Length", "" + file.length());
			OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
			response.setContentType("application/octet-stream");
			toClient.write(buffer);
			toClient.flush();
			toClient.close();
		} catch (Exception e) {
			e.printStackTrace();
			throw new AppException(BasicErrorCode.DEFINED_MSG, "下载模板失败");
		}
	}
	
	@ApiOperation(value = "批量导入", notes = "批量导入：xls xlsx")
	@RequestMapping(value = "/import", method = { RequestMethod.POST }, produces = "application/json;charset=UTF-8")
	@RequiresPermissions("school:student:import")
	@ResponseBody
	public MultiResponse batchImport(@RequestParam("file") @Valid MultipartFile upFile,
			@RequestParam("schoolId") @Valid Long schoolId,@RequestParam("classId") @Valid Long classId,
			@RequestParam("grade") @Valid Integer grade) {
		String[] allowedType = { "application/vnd.ms-excel","application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" };
		boolean allowed = Arrays.asList(allowedType).contains(upFile.getContentType());
		if (!allowed) {
			throw new AppException(BasicErrorCode.FILE_FORMAT);
		}
		
		List<BatchImportStudentEntity> returnList = new ArrayList<>();
		List<BatchImportStudentEntity> saveList = new ArrayList<>();
		
		InputStream in = null;
		try {
			in = upFile.getInputStream();
			EasyExcel.read(in, BatchImportStudentEntity.class, new UploadStudentExcelListener()).sheet("Sheet1").doRead();
			for (BatchImportStudentEntity student : UploadStudentExcelListener.list) {
				String message = "";
				boolean returnFlag = false;
				BatchImportStudentEntity entity = new BatchImportStudentEntity();
				BeanUtil.copyProperties(student, entity);
				
				if (studentService.queryStudentSNExisit(student.getSn(), getPartyId())) {
					message = student.getSn()+"已存在";
					returnFlag = true;
				}
				if (StringUtil.isBlank(student.getBirthday())) {
					message = "出生日期未填写完整";
					returnFlag = true;
				}
				if (StringUtil.isBlank(student.getHeight())) {
					message = "身高未填写完整";
					returnFlag = true;
				}
				if (StringUtil.isBlank(student.getWeight())) {
					message = "体重未填写完整";
					returnFlag = true;
				}
				
				if (returnFlag) {
					entity.setMessage(message);
					returnList.add(entity);
				} else {
					saveList.add(entity);
				}
			}
			
			// 没有错误信息时批量保存
			if (0 == returnList.size()) {
				studentService.batchSave(saveList, getPartyId(), getUserId(), schoolId, grade, classId);
			}
			
			UploadStudentExcelListener.list.clear();
		} catch (Exception e) {
			e.printStackTrace();
			throw new AppException(BasicErrorCode.DEFINED_MSG, "批量导入班级失败");
		}
		
		return MultiResponse.ofWithoutTotal(returnList);
	}
	
	@ApiOperation(value = "批量导出", notes = "批量导出：导出为xls文档")
	@ApiImplicitParam(name = "request", value = "请求对象", required = true, dataType = "QueryStudentReq")
	@RequiresPermissions("school:student:export")
	@PostMapping("/export")
	public void export(@RequestBody QueryStudentReq request, HttpServletResponse response) {
		request.setPartyId(getPartyId());
		request.setPageSize(5000);
		List<StudentExportResp> list = studentService.queryExportList(request);
		if (list.size() != 0) {
			ExcelWriter writer = ExcelUtil.getWriter();
			
			// 自定义标题别名
			writer.addHeaderAlias("name", "姓名");
			writer.addHeaderAlias("sexCn", "性别");
			writer.addHeaderAlias("termBeginTime", "入学年份");
			writer.addHeaderAlias("schoolName", "校区");
			writer.addHeaderAlias("gradeName", "所在年级");
			writer.addHeaderAlias("className", "所在班级");
			writer.addHeaderAlias("classType", "班级类型");
			writer.addHeaderAlias("number", "编号");
			writer.addHeaderAlias("sn", "学号");
			writer.addHeaderAlias("statusCn", "状态");
			writer.addHeaderAlias("createTime", "创建时间");
			writer.write(list, true);
			response.setContentType("application/vnd.ms-excel;charset=utf-8");
			String fileName = "学生";
			SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
			try {
				fileName = new String(fileName.getBytes(), "iso8859-1") + dateFormat.format(new Date());
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
			response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xls");
			ServletOutputStream out = null;
			try {
				out = response.getOutputStream();
				writer.flush(out, true);
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				writer.close();
			}
			IoUtil.close(out);
		}
	}
    
}
